﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading;
using OpenQA.Selenium;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Safari;

namespace WebAutomation.Browsers.Safari
{
    public class SafariBrowser:WebBrowserObject
    {
        private SafariDriver _safari;
        public SafariBrowser()
        {
            var listOfBrowsers = System.Diagnostics.Process.GetProcessesByName("Safari");
            foreach (var items in listOfBrowsers)
            {
                items.Kill();
            }
            SafariOptions options = new SafariOptions();
            options.Port = 8181;
            _safari = new SafariDriver(options);
            

        }

        

        private void _highlightElement(IWebElement element)
        {
            _safari.ExecuteScript("arguments[0].style.backgroundColor='yellow'", element);

        }

        private string _getFindValue(WatiN.Core.Constraints.Constraint find)
        {
            string returnValue = "";
            string[] findByArray = find.ToString().Replace("Attribute ", "").Replace(" equals ", "^").Split('^');
            string findBy = findByArray[0].Replace("'", "");
            string findValue = findByArray[1].Replace("'", "");
            returnValue = findValue;
            return returnValue;

        }



        private IWebElement _getChromeWebElement(WatiN.Core.Constraints.Constraint find, string attributeValue = "",bool checkIframe=false,IWebElement iframe=null)
        {
            if(checkIframe)
            {
                if(iframe!=null)
                {
                    _safari.SwitchTo().Frame(iframe);
                }
            }
            string findValue = attributeValue;
            if (find != null)
            {
                findValue = _getFindValue(find);
            }
            IWebElement element = null;
            bool found = false;
            try
            {
                element = _safari.FindElement(By.Name(findValue));
                found = true;
            }
            catch
            {

            }
            if (!found)
            {
                try
                {
                    element = _safari.FindElement(By.Id(findValue));
                    found = true;
                }
                catch
                {

                }
            }
            //_chrome.FindElementByXPath("//a[@id='"+id+"']");
            if (!found)
            {
                try
                {
                    element = _safari.FindElement(By.ClassName(findValue));
                    found = true;
                }
                catch
                {

                }
            }

            return element;
        }

        public override int ProcessID
        {
            get
            {
                int returnValue = 0;
                System.Diagnostics.Process[] listOfBrowsers = System.Diagnostics.Process.GetProcessesByName("Safari");
                foreach(var item in listOfBrowsers)
                {
                    returnValue = item.Id;
                    break;

                }


                return returnValue;
            }
        }

        public override WebBrowserObject.ElementProperties Button(WatiN.Core.Constraints.Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();

            IWebElement element = _getChromeWebElement(find);

            if (element != null)
            {

                elementProperties.Element = element;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override void ButtonWaitUntilExists(WatiN.Core.Constraints.Constraint find)
        {
            
        }

        public override void DivWaitUntilAttributeValue(string divID, string attributeName, string expectedValue)
        {
           
        }

        public override void WaitForComplete()
        {
            _waitForPageToLoad(20000);
        }

        public override WebBrowserObject.ElementProperties CheckBox(WatiN.Core.Constraints.Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();

            IWebElement element = _getChromeWebElement(find);

            if (element != null)
            {

                elementProperties.Element = element;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override object Div(WatiN.Core.Constraints.Constraint find)
        {
            IWebElement element =null;
            element = _getChromeWebElement(find);

            return element;
            
        }

        public override object DomContainer()
        {
            return null;
        }

        public override void CaptureWebPageAsImage(string imageFileName, string imageQualityString, int imageQuality)
        {
            Screenshot ss = ((ITakesScreenshot)_safari).GetScreenshot();
            ss.SaveAsFile(imageFileName, ImageFormat.Jpeg); 
        }

        public override WebBrowserObject.ElementProperties Element(WatiN.Core.Constraints.Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();

            IWebElement element = _getChromeWebElement(find);

            if (element != null)
            {

                elementProperties.Element = element;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override WebBrowserObject.ElementProperties Element()
        {
            WatiN.Core.Element element = null;
            ElementProperties elementProperties = new ElementProperties();
            elementProperties.Element = element;
            return new ElementProperties();
        }

        public override Dictionary<int, object> Frames()
        {
            Dictionary<int, object> returnValue = new Dictionary<int, object>();
            ReadOnlyCollection<IWebElement> list = null;
            try
            {
                list = _safari.FindElements(By.XPath("//iframe"));
            }catch{}
            if(list!=null)
            {
                if(list.Count>0)
                {
                    int i = 0;
                    foreach(var item in list)
                    {
                        returnValue.Add(i, item);
                        i++;
                    }

                }

            }


            return returnValue;
        }

        public override void WaitForCompleteIFrame(int iframeIndex, int secondsToWait)
        {
            var frame = _safari.FindElements(By.XPath("//iframe"))[iframeIndex];

            _waitForPageToLoad(secondsToWait);
        }

        public override WebBrowserObject.ElementProperties ElementIFrame(int iframeIndex, string idOrNameOrClassOrValue)
        {
            var frame = _safari.FindElements(By.XPath("//iframe"))[iframeIndex];
            _safari.SwitchTo().Frame(frame);
            ElementProperties elementProperties = new ElementProperties();

            IWebElement element = _getChromeWebElement(null, idOrNameOrClassOrValue, true, frame);

            if (element != null)
            {

                elementProperties.Element = element;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override void GoTo(string url)
        {
            _safari.Navigate().GoToUrl(url);
        }

        public override string Html()
        {
            string returnValue = "";
            bool isError = false;
            try
            {
                returnValue = _safari.PageSource;
            }catch
            {
                isError = true;
            }
            if (isError || string.IsNullOrEmpty(returnValue))
            {
                _safari.SwitchTo().DefaultContent();
                returnValue = _safari.PageSource;
            }

            return returnValue;
        }

        public override string HtmlIFrame(int iframeIndex)
        {
            string returnValue = "";
            var frame = _safari.FindElements(By.XPath("//iframe"))[iframeIndex];
            returnValue = _safari.SwitchTo().Frame(frame).PageSource;
            return returnValue;
        }

        public override WebBrowserObject.ElementProperties Link(string attributeValue)
        {
            ElementProperties elementProperties = new ElementProperties();

            IWebElement element = _getChromeWebElement(null, attributeValue);

            if (element != null)
            {

                elementProperties.Element = element;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override Dictionary<int, object> FrameLinks(int iframeIndex)
        {
            Dictionary<int, object> returnValue = new Dictionary<int, object>();
            var frame = _safari.FindElements(By.XPath("//iframe"))[iframeIndex];
            _safari.SwitchTo().Frame(frame);
            var listofLinks = _safari.FindElements(By.XPath("//a"));
            int i = 0;
            foreach (var links in listofLinks)
            {
                returnValue.Add(i, links);
                i++;
            }


            return returnValue;
        }

        public override string GetIFrameLinkAttributeValue(int iframeIndex, int linkIndex, string attributeName)
        {
            string returnValue = "";
            var frame = _safari.FindElements(By.XPath("//iframe"))[iframeIndex];
            _safari.SwitchTo().Frame(frame);
            var listofLinks = _safari.FindElements(By.XPath("//a"));
            returnValue=listofLinks[linkIndex].GetAttribute(attributeName);

            return returnValue;
        }

        public override string GetIFrameLinkClassName(int iframeIndex, int linkIndex)
        {
            string returnValue = "";
            var frame = _safari.FindElements(By.XPath("//iframe"))[iframeIndex];
            _safari.SwitchTo().Frame(frame);
            var listofLinks = _safari.FindElements(By.XPath("//a"));
            returnValue = listofLinks[linkIndex].GetAttribute("class");

            return returnValue;
        }

        public override void RunScript(string scriptToRun)
        {
            _safari.ExecuteScript(scriptToRun);
        }

        public override WebBrowserObject.ElementProperties SelectList(WatiN.Core.Constraints.Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();

            IWebElement element = _getChromeWebElement(find);

            if (element != null)
            {

                elementProperties.Element = element;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override void CheckBoxCheck(object checkBox, string valueOrId)
        {
        
            IWebElement element = (RemoteWebElement)checkBox;
            bool isError = false;
            try
            {
                element.Click();
            }
            catch
            {
                isError = true;
            }
            if (isError)
            {
                //maybe its in the iframe
                _safari.SwitchTo().DefaultContent();
                element.Click();
               
            }

            
        }

        public override void ElementClick(object element)
        {
            IWebElement elem = (RemoteWebElement)element;
            bool isError = false;
            try
            {
                elem.Click();
            }
            catch
            {
                isError = true;
            }
            if (isError)
            {
                //maybe its in the iframe
                _safari.SwitchTo().DefaultContent();
                elem.Click();
            }
        }

        public override bool SelectListSelect(object element, string selectListValue)
        {
            bool returnValue = false;
            IWebElement elem = (RemoteWebElement)element;
            string foundBy = "id";
            string id = elem.GetAttribute("id");
            if(string.IsNullOrEmpty(id))
            {
                foundBy = "name";
                id = elem.GetAttribute("name");
            }


            bool isError = false;
            try
            {
                if (foundBy == "id")
                {
                    _safari.FindElement(By.Id(id)).FindElement(By.CssSelector("option[value='" + selectListValue + "']"))
                        .Click();
                    returnValue = true;
                }else
                {
                    _safari.FindElement(By.Name(id)).FindElement(By.CssSelector("option[value='" + selectListValue + "']"))
                        .Click();
                    returnValue = true;
                }
            }
            catch
            {
                isError = true;
            }
            if (isError)
            {
                //maybe its in the iframe
                _safari.SwitchTo().DefaultContent();
                if (foundBy == "id")
                {
                    _safari.FindElement(By.Id(id)).FindElement(By.CssSelector("option[value='" + selectListValue + "']"))
                        .Click();
                    returnValue = true;
                }
                else
                {
                    _safari.FindElement(By.Name(id)).FindElement(By.CssSelector("option[value='" + selectListValue + "']"))
                        .Click();
                    returnValue = true;
                }
            }

            return returnValue;
        }

        public override void ShowWindow(WatiN.Core.Native.Windows.NativeMethods.WindowShowStyle windowShowStyle)
        {
            
        }

        

        public override WebBrowserObject.ElementProperties TextField(WatiN.Core.Constraints.Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();
            
            IWebElement element = _getChromeWebElement(find);

            if (element!=null)
            {

                elementProperties.Element = element;
                elementProperties.Exists = true;
            }

            return elementProperties;

        }

        public override WebBrowserObject.ElementProperties TextFieldIFrame(int iframeIndex, WatiN.Core.Constraints.Constraint find)
        {
            var frame = _safari.FindElements(By.XPath("//iframe"))[iframeIndex];
            _safari.SwitchTo().Frame(frame);
            ElementProperties elementProperties = new ElementProperties();
            IWebElement element = _getChromeWebElement(find);
            if (element != null)
            {
                elementProperties.Element = element;
                elementProperties.Exists = true;
            }
            
            return elementProperties;


        }

        

        public override void TypeText(object textField, string textValueToType,WebBrowserObject browserObject)
        {
            IWebElement element = (RemoteWebElement) textField;
            bool isError = false;
            bool hasOnchangeEvent = false;
            string onchangeJS = "";
            try
            {
                _safari.ExecuteScript("arguments[0].value=''", element);
                element.SendKeys(textValueToType);
                try
                {
                    if (element.GetAttribute("onchange") != "")
                    {
                        onchangeJS = element.GetAttribute("onchange");
                        hasOnchangeEvent = true;
                    }
                }catch{}

                if (hasOnchangeEvent && !string.IsNullOrEmpty(onchangeJS))
                {
                    _safari.ExecuteScript(onchangeJS);
                }
                _highlightElement(element);
            }catch
            {
                isError = true;
            }
            
            if (isError)
            {
                //maybe its in the iframe
                _safari.SwitchTo().DefaultContent();
                _safari.ExecuteScript("arguments[0].value=''", element);
                element.SendKeys(textValueToType);
                try
                {
                    if (element.GetAttribute("onchange") != "")
                    {
                        onchangeJS = element.GetAttribute("onchange");
                        hasOnchangeEvent = true;
                    }
                }
                catch { }

                if (hasOnchangeEvent && !string.IsNullOrEmpty(onchangeJS))
                {
                    _safari.ExecuteScript(onchangeJS);
                }


                _highlightElement(element);
            }
            
            

            
            Thread.Sleep(500);
        }

        public override WebBrowserObject.ElementProperties ButtonIFrame(int iframeIndex, WatiN.Core.Constraints.Constraint find)
        {
            var frame = _safari.FindElements(By.XPath("//iframe"))[iframeIndex];
            _safari.SwitchTo().Frame(frame);
            ElementProperties elementProperties = new ElementProperties();
            IWebElement element = _getChromeWebElement(find);
            if (element != null)
            {
                elementProperties.Element = element;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override void ButtonClick(object buttonField)
        {
            IWebElement element = (RemoteWebElement)buttonField;
            bool isError = false;
            try
            {
                _highlightElement(element);
                element.Click();
                
            }
            catch
            {
                isError = true;
            }
            if (isError)
            {
                //maybe its in the iframe
                _safari.SwitchTo().DefaultContent();
                _highlightElement(element);
                element.Click();
            }
            _waitForPageToLoad(8000);
        }

        public override void ButtonMouseDown(object buttonField)
        {
            IWebElement element = (RemoteWebElement)buttonField;
            bool isError = false;
            try
            {
                _highlightElement(element);
                element.Click();
            }
            catch
            {
                isError = true;
            }
            if (isError)
            {
                //maybe its in the iframe
                _safari.SwitchTo().DefaultContent();
                _highlightElement(element);
                element.Click();
            }
            
        }

        public override void ButtonMouseUp(object buttonField)
        {
            IWebElement element = (RemoteWebElement)buttonField;
            bool isError = false;
            try
            {
                _highlightElement(element);
                element.Click();
            }
            catch
            {
                isError = true;
            }
            if (isError)
            {
                //maybe its in the iframe
                _safari.SwitchTo().DefaultContent();
                _highlightElement(element);
                element.Click();
            }
        }

        public override string GetLinkAttributeValue(object link, string attributeToGet)
        {
            IWebElement element = (RemoteWebElement)link;
            string value ="";
            try
            {
                value = element.GetAttribute(attributeToGet);
            }catch
            {
                
            }
            return value;
        }

        private void _waitForPageToLoad(int milliseconds)
        {
           // _chrome.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(seconds));
            Thread.Sleep(milliseconds);

        }

        public override void LinkClick(object link)
        {
            IWebElement element = (RemoteWebElement)link;
            bool isError = false;
            try
            {
                _highlightElement(element);
                element.Click();
            }
            catch
            {
                isError = true;
            }
            if (isError)
            {
                //maybe its in the iframe
                _safari.SwitchTo().DefaultContent();
                _highlightElement(element);
                element.Click();
            }
            _waitForPageToLoad(5000);

        }

        private string _getElementAttribute(IWebElement element,string attributeToGet)
        {
            string returnValue = "";
            try
            {
                returnValue = element.GetAttribute(attributeToGet);
            }catch
            {
                
            }

            return returnValue;
        }

        public override Dictionary<int, WebBrowserObject.ElementProperties> Elements()
        {
            Dictionary<int, ElementProperties> list = new Dictionary<int, ElementProperties>();
            int i = 0;
            foreach (var items in _safari.FindElements(By.XPath("//input")))
            {
                
                ElementProperties elementProperties = new ElementProperties();
                elementProperties.Exists = true;
                elementProperties.Element = items;
                elementProperties.ElementType = items.GetType().ToString();
                elementProperties.ElementHTMLType = items.TagName;

                elementProperties.ElementAttributes = new Dictionary<string, string>();
                elementProperties.ElementAttributes.Add("Type", _getElementAttribute(items, "type"));
                elementProperties.ElementAttributes.Add("Name", _getElementAttribute(items, "name"));
                elementProperties.ElementAttributes.Add("ID", _getElementAttribute(items, "id"));
                elementProperties.ElementAttributes.Add("ClassName", _getElementAttribute(items, "class"));
                elementProperties.ElementAttributes.Add("Style", _getElementAttribute(items, "style"));
                elementProperties.ElementAttributes.Add("Value", _getElementAttribute(items, "value"));
                elementProperties.ElementAttributes.Add("Click", _getElementAttribute(items, "click"));
                elementProperties.ElementAttributes.Add("Change", _getElementAttribute(items, "change"));
                elementProperties.ElementAttributes.Add("Href", _getElementAttribute(items, "href"));

                list.Add(i, elementProperties);
                i++;
            }

            int ii = i + 1;
            foreach (var items in _safari.FindElements(By.XPath("//a")))
            {

                ElementProperties elementProperties = new ElementProperties();
                elementProperties.Exists = true;
                elementProperties.Element = items;
                elementProperties.ElementType = items.GetType().ToString();
                elementProperties.ElementHTMLType = items.TagName;

                elementProperties.ElementAttributes = new Dictionary<string, string>();
                elementProperties.ElementAttributes.Add("Type", _getElementAttribute(items, "type"));
                elementProperties.ElementAttributes.Add("Name", _getElementAttribute(items, "name"));
                elementProperties.ElementAttributes.Add("ID", _getElementAttribute(items, "id"));
                elementProperties.ElementAttributes.Add("ClassName", _getElementAttribute(items, "class"));
                elementProperties.ElementAttributes.Add("Style", _getElementAttribute(items, "style"));
                elementProperties.ElementAttributes.Add("Value", _getElementAttribute(items, "value"));
                elementProperties.ElementAttributes.Add("Click", _getElementAttribute(items, "click"));
                elementProperties.ElementAttributes.Add("Change", _getElementAttribute(items, "change"));
                elementProperties.ElementAttributes.Add("Href", _getElementAttribute(items, "href"));

                list.Add(ii, elementProperties);
                ii++;
            }

            int iii = ii + 1;
            foreach (var items in _safari.FindElements(By.XPath("//div")))
            {

                ElementProperties elementProperties = new ElementProperties();
                elementProperties.Exists = true;
                elementProperties.Element = items;
                elementProperties.ElementType = items.GetType().ToString();
                elementProperties.ElementHTMLType = items.TagName;

                elementProperties.ElementAttributes = new Dictionary<string, string>();
                elementProperties.ElementAttributes.Add("Type", _getElementAttribute(items, "type"));
                elementProperties.ElementAttributes.Add("Name", _getElementAttribute(items, "name"));
                elementProperties.ElementAttributes.Add("ID", _getElementAttribute(items, "id"));
                elementProperties.ElementAttributes.Add("ClassName", _getElementAttribute(items, "class"));
                elementProperties.ElementAttributes.Add("Style", _getElementAttribute(items, "style"));
                elementProperties.ElementAttributes.Add("Value", _getElementAttribute(items, "value"));
                elementProperties.ElementAttributes.Add("Click", _getElementAttribute(items, "click"));
                elementProperties.ElementAttributes.Add("Change", _getElementAttribute(items, "change"));
                elementProperties.ElementAttributes.Add("Href", _getElementAttribute(items, "href"));

                list.Add(iii, elementProperties);
                iii++;
            }

            return list;

        }

        public override string GetIFrameAttributeValue(int iframeIndex, string attributeName)
        {
            string returnValue = "";
            var frame = _safari.FindElements(By.XPath("//iframe"))[iframeIndex];
            _safari.SwitchTo().Frame(frame);
            try
            {
                returnValue = frame.GetAttribute(attributeName);
            }catch{}
            return returnValue;
            
        }

        public override bool ElementExist(object element)
        {
            bool returnValue = false;
            IWebElement ele = null;
            try
            {
                ele = (RemoteWebElement) element;
                
            }catch
            {
                
            }
            if(ele!=null)
            {
                returnValue = true;
            }

            return returnValue;
        }

        public override WebBrowserObject.ElementProperties RadioButton(WatiN.Core.Constraints.Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();

            IWebElement element = _getChromeWebElement(find);

            if (element != null)
            {

                elementProperties.Element = element;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override void RadioButtonCheck(object radioButton, string valueOrId)
        {
            IWebElement element = (RemoteWebElement)radioButton;
            bool isError = false;
            try
            {
                _highlightElement(element);
                element.Click();
            }
            catch
            {
                isError = true;
            }
            if (isError)
            {
                //maybe its in the iframe
                _safari.SwitchTo().DefaultContent();
                _highlightElement(element);
                element.Click();
            }
        }

        public override bool Dispose()
        {
            try
            {
                _safari.Dispose();
                System.Diagnostics.Process[] listOfBrowsers = System.Diagnostics.Process.GetProcessesByName("chrome");
                foreach(var items in listOfBrowsers)
                {
                    items.Kill();
                }

                listOfBrowsers = System.Diagnostics.Process.GetProcessesByName("chromedriver");
                foreach (var items in listOfBrowsers)
                {
                    items.Kill();
                }

            }catch
            {
                return false;
            }

            return true;
        }

        public override WebBrowserObject.ElementProperties GetLinkByText(string text, int index)
        {
            throw new NotImplementedException();
        }

        public override void WinFormType(int winHandle, string textBoxId, string textToType)
        {
            throw new NotImplementedException();
        }

        public override void KeyPressEnter(object textField, string keyName, WebBrowserObject browserObject)
        {
            throw new NotImplementedException();
        }

        public override void Refresh(string keys)
        {
            throw new NotImplementedException();

        }
    }
}
